{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 前言\n",
    "\n",
    "我们在学习过程中经常会看到这样或者那样的错误，学会读懂错误，也是很重要的。\n",
    "\n",
    "最常见的几种错误：\n",
    "\n",
    "- 语法错误\n",
    "- 名字错误\n",
    "- 类型错误\n",
    "- 文件不存在错误\n",
    "\n",
    "在编程过程中，出现错误是难免的，尤其是你在运行一些别人的代码的时候。这节课，我们就来讲讲 Python 的错误和异常该如何处理。\n",
    "\n",
    "本节课程你将学到：\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "ename": "SyntaxError",
     "evalue": "EOL while scanning string literal (<ipython-input-4-cc6d3073532a>, line 1)",
     "output_type": "error",
     "traceback": [
      "\u001b[0;36m  File \u001b[0;32m\"<ipython-input-4-cc6d3073532a>\"\u001b[0;36m, line \u001b[0;32m1\u001b[0m\n\u001b[0;31m    print(\"hello world\u001b[0m\n\u001b[0m                      ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m EOL while scanning string literal\n"
     ]
    }
   ],
   "source": [
    "print(\"hello world"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 解读\n",
    "\n",
    "观察上面的代码和输出，最后一行最明显，Python 程序提示出现了一个 SyntaxError，也就是「语法错误」。\n",
    "\n",
    "同时你看倒数第二行，可以看到有个小箭头，指向我们错误发生的位置，在world后面。\n",
    "\n",
    "我们继续看最后一行关于错误的具体描述，「在扫描字符串的时候遇到了 EOL」。这里的 EOL 是 end of line（行尾）的缩写。\n",
    "\n",
    "而第一行，是说明文件名和行号，错误发生在哪个文件的哪行代码。\n",
    "\n",
    "## 语法错误（SyntaxError）\n",
    "\n",
    "语法错误一般比较容易发现。\n",
    "\n",
    "## 代码异常（Exception）\n",
    "\n",
    "而更多的时候，是语法没有问题，但是运行起来出现错误。\n",
    "\n",
    "我们来看几个异常的错误，这些都是来自官方的文档。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "ename": "ZeroDivisionError",
     "evalue": "division by zero",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mZeroDivisionError\u001b[0m                         Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-6-6de6d1297d43>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m      1\u001b[0m \u001b[0;31m# 案例1\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0;36m10\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m/\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;31mZeroDivisionError\u001b[0m: division by zero"
     ]
    }
   ],
   "source": [
    "# 案例1：把 0 当作除数\n",
    "10*(1/0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "ename": "NameError",
     "evalue": "name 'spam' is not defined",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mNameError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-7-75d5320ce639>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m      1\u001b[0m \u001b[0;31m# 案例2\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0;36m4\u001b[0m\u001b[0;34m+\u001b[0m\u001b[0mspam\u001b[0m\u001b[0;34m+\u001b[0m\u001b[0;36m3\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;31mNameError\u001b[0m: name 'spam' is not defined"
     ]
    }
   ],
   "source": [
    "# 案例2：spam 名字尚未定义\n",
    "4+spam+3"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "ename": "TypeError",
     "evalue": "can only concatenate str (not \"int\") to str",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-10-816dd142d35d>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m      1\u001b[0m \u001b[0;31m# 案例3：类型不同\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0;34m'2'\u001b[0m\u001b[0;34m+\u001b[0m\u001b[0;36m2\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;31mTypeError\u001b[0m: can only concatenate str (not \"int\") to str"
     ]
    }
   ],
   "source": [
    "# 案例3：类型不同\n",
    "'2'+2"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 解读\n",
    "\n",
    "以上三段代码一共出现三种异常，分别是：\n",
    "\n",
    "1. ZeroDivisionError（除零异常）\n",
    "2. NameError（名字异常）\n",
    "3. TypeError（类型异常）\n",
    "\n",
    "以上都是异常的类型，其实这里涉及到了面向对象编程里面的类，这个在 Python 进阶里面的[类]()会讲到。\n",
    "\n",
    "我们还是回过来看看上面每个异常的具体描述，三个分别是什么。\n",
    "\n",
    "同样的，我们也看到除了出错的位置，还有一个叫「Traaceback」的提示，它的意思就是追溯（最近一次的执行），而且阅读的方式应该是自上而下，我们这里写的比较简单所以看不出来，我们来稍微复杂一点。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "ename": "ZeroDivisionError",
     "evalue": "division by zero",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mZeroDivisionError\u001b[0m                         Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-13-d570115b74ec>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m      3\u001b[0m     \u001b[0;32mreturn\u001b[0m \u001b[0ma\u001b[0m \u001b[0;34m/\u001b[0m \u001b[0mb\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      4\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 5\u001b[0;31m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdevide\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;32m<ipython-input-13-d570115b74ec>\u001b[0m in \u001b[0;36mdevide\u001b[0;34m(a, b)\u001b[0m\n\u001b[1;32m      1\u001b[0m \u001b[0;31m# 定义函数\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      2\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mdevide\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0ma\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0mb\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m     \u001b[0;32mreturn\u001b[0m \u001b[0ma\u001b[0m \u001b[0;34m/\u001b[0m \u001b[0mb\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m      4\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      5\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdevide\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;31mZeroDivisionError\u001b[0m: division by zero"
     ]
    }
   ],
   "source": [
    "# 定义函数\n",
    "def devide(a,b):\n",
    "    return a / b\n",
    "\n",
    "print(devide(1,0))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 解读\n",
    "\n",
    "这样我们是不是可以清晰的看到先是第5行`print()`里面出错了，再深究下去，就是定义的`devide`函数出错了，什么错误？是「除零错误」。同时你也可以看到`in <module>`和`in devide(a,b)`都是明确表明错误发生的位置的。\n",
    "\n",
    "module 翻译为模组，跟它的发音很像，表示错误发生在代码的最外层。\n",
    "\n",
    "当然我们这里的问题比较简单，比较复杂的时候就需要我们根据这些提示来好好分析了。\n",
    "\n",
    "关于函数定义 def，我们在 Python 进阶里面的[定义函数]()会讲到。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 其他异常\n",
    "\n",
    "除了常见的，还有很多异常类型，\n",
    "\n",
    "未来在你自己编写的过程中也会遇到各种各样的异常。\n",
    "\n",
    "但是通常这些异常都可以通过以上方式来解决。\n",
    "\n",
    "# 异常解决的好方法\n",
    "\n",
    "遇到异常，最简单直接的方式就是把异常拿到搜索引擎，找到最佳的解决方案，通常最好的答案会在这里：\n",
    "[stackoverflow](https://stackoverflow.com/)\n",
    "\n",
    "当然你也可以研究：\n",
    "[python 官方文档](https://docs.python.org/3/)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 异常的预判和防护\n",
    "\n",
    "让我来回到我们之前提到的一个小游戏，就是下面这段代码："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "请输入一个[1,100]的整数：abc\n"
     ]
    },
    {
     "ename": "ValueError",
     "evalue": "invalid literal for int() with base 10: 'abc'",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mValueError\u001b[0m                                Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-1-4feaf0bf5dce>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m      6\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      7\u001b[0m \u001b[0;32mwhile\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mis_done\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 8\u001b[0;31m     \u001b[0mguess\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0minput\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'请输入一个[1,100]的整数：'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m      9\u001b[0m     \u001b[0;32mif\u001b[0m \u001b[0mguess\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0mnum\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     10\u001b[0m         \u001b[0mis_done\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;32mTrue\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;31mValueError\u001b[0m: invalid literal for int() with base 10: 'abc'"
     ]
    }
   ],
   "source": [
    "import random\n",
    "\n",
    "num = random.randint(1,100)  # 获取一个1-100间的随机数\n",
    "is_done = False # 是否猜中的标记\n",
    "count = 0 # 玩家玩了几次\n",
    "\n",
    "while not is_done:\n",
    "    guess = int(input('请输入一个[1,100]的整数：'))\n",
    "    if guess == num:\n",
    "        is_done = True\n",
    "    elif guess > num:\n",
    "        print('大了，再猜猜')\n",
    "    elif guess < num:\n",
    "        print('小了，再猜猜')\n",
    "    count += 1\n",
    "    \n",
    "print('恭喜你，猜了{}次，终于猜对了！答案是{}!'.format(count,num))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 解读\n",
    "\n",
    "第 8 行，我们用 input 函数来接受数据并返回字符串，用 int 函数讲字符串转换成[整形]()\n",
    "\n",
    "那要是有个用户调皮，他没有输入整数，他输入了其他的字符串呢？\n",
    "\n",
    "（**动手试试吧！**）\n",
    "\n",
    "试过之后，我们可以看到，程序抛出了一个 `ValueError`的错误，具体解释是「abc 这个无效输入，无法被转换成 10 进制的整数」。\n",
    "\n",
    "因为我们没有对异常进行任何处理，所以当用户不小心输入了不符合规则的字符，就会抛出异常退出程序。\n",
    "\n",
    "我们可以检查用户的输入，判断用户是否输入了合法的字符，在输入合法的时候，才将用户输入转换为整数。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "输入一个整数：asdf\n",
      "您输入的不是整数：asdf\n"
     ]
    }
   ],
   "source": [
    "guess_str = input('输入一个整数：')\n",
    "\n",
    "if str.isdecimal(guess_str):\n",
    "    guess = int(guess_str)\n",
    "else:\n",
    "    print('您输入的不是整数：' + guess_str)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在日常写代码中，有很多类似的异常情况需要我们去考虑。特别是当我们面对用户输入的时候，如果我们盲目信任用户的输入，那么不仅可能造成程序崩溃、结果错误，甚至，当我们的代码在网络上运行时，还会引发许多安全问题，使得我们暴露在骇客的攻击之下。\n",
    "\n",
    "在编码过程中对各种异常情况的防范处理，我们称作防御性编程。有很多资料为大家提供了防御性编程的介绍、建议等，建议同学们搜索学习一下，为安全编程打下意识基础。\n",
    "\n",
    "上面的代码里，我们使用了 IF 语句来对用户输入进行了额外的判断。实际上，使用 Python 的异常处理功能，能够更加简单优雅地解决这个问题。我们还是先来看例子："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "ename": "SyntaxError",
     "evalue": "'continue' not properly in loop (<ipython-input-8-c7cf18e4af2f>, line 8)",
     "output_type": "error",
     "traceback": [
      "\u001b[0;36m  File \u001b[0;32m\"<ipython-input-8-c7cf18e4af2f>\"\u001b[0;36m, line \u001b[0;32m8\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m 'continue' not properly in loop\n"
     ]
    }
   ],
   "source": [
    "try:\n",
    "    guess = int(input('输入一个整数：'))\n",
    "except ValueError:\n",
    "    print('输入错误，请您再试一次')\n",
    "    continue"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 解读\n",
    "这段代码里，使用了 Python 的 try 和 except 关键字。这个语句的意思可以理解为：尝试运行 try 关键字后面的语句，如果代码运行没有问题，那么语句运行结束；如果代码抛出了 ValueError 异常，那么就执行 except 后面的语句。\n",
    "\n",
    "在我们游戏代码的循环语句中，我们可以使用类似的代码包裹用户输入的语句，并且在 except 后面的语句块中加一句 continue。这样，在用户输入错误抛出异常时，我们就结束当前循环的运行，进入下一次循环，让用户重新输入。大家可以自己尝试改写一下，或者拷贝可乐代码仓库中的代码，试一下看是不是游戏体验好了很多呢？"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {
    "code_folding": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "请输入一个[1,100]的整数：50\n",
      "大了，再猜猜\n",
      "请输入一个[1,100]的整数：25\n",
      "大了，再猜猜\n",
      "请输入一个[1,100]的整数：20\n",
      "大了，再猜猜\n",
      "请输入一个[1,100]的整数：10\n",
      "小了，再猜猜\n",
      "请输入一个[1,100]的整数：15\n",
      "小了，再猜猜\n",
      "请输入一个[1,100]的整数：16\n",
      "恭喜你，猜了6次，终于猜对了！答案是16!\n"
     ]
    }
   ],
   "source": [
    "import random\n",
    "\n",
    "num = random.randint(1,100)  # 获取一个1-100间的随机数\n",
    "is_done = False # 是否猜中的标记\n",
    "count = 0 # 玩家玩了几次\n",
    "\n",
    "while not is_done:\n",
    "    try:\n",
    "        guess = int(input('请输入一个[1,100]的整数：'))\n",
    "    except ValueError:\n",
    "        print('输入错误，请您再试一次')\n",
    "        continue\n",
    "    if guess > 100 or guess < 1:\n",
    "        print('输入超出范围，请您再试一次')\n",
    "    else: \n",
    "        if guess == num:\n",
    "            is_done = True\n",
    "        elif guess > num:\n",
    "            print('大了，再猜猜')\n",
    "        elif guess < num:\n",
    "            print('小了，再猜猜')\n",
    "    count += 1\n",
    "    \n",
    "print('恭喜你，猜了{}次，终于猜对了！答案是{}!'.format(count,num))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 解读\n",
    "上面这种代码叫做异常的捕获处理。使用异常捕获，捕获了异常之后，通常我们会提示用户、记录日志，或者改变代码执行流程，就像上面的 continue 语句一样。和 IF 语句的 ELIF 子句类似，except 子句也可以重复多次；此外，和 IF 语句的 ELSE 子句类似，可以在 try 语句的最后使用 finally 关键字，Python 则会保证 finally 语句块中的代码总是会被运行；\n",
    "\n",
    "try 语句自己也支持 else 子句，这里的代码则在没有异常出现的时候总是会运行。我们来看下面的例子："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "输入中断\n",
      "这句话总是会执行\n",
      "输入一个整数：abc\n"
     ]
    }
   ],
   "source": [
    "try:\n",
    "    guess = int(input('输入一个整数：')) # 仍然是提示用户输入整数\n",
    "except ValueError:\n",
    "    print('输入错误，请您再试一次') # 提示用户输入错误\n",
    "except KeyboardInterrupt: # 然后，我们捕获另一个异常，KeyboardInterrupt\n",
    "    print('输入中断') # 这个异常表示输入中断，我们提示给用户\n",
    "else: # 我们加入 else 子句\n",
    "    print('输入正常') # else 子句总是在代码没有异常时运行，我们提示用户\n",
    "finally: # 最后，我们加入 finally 子句\n",
    "    print('这句话总是会执行')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这段代码里的   是一个特殊的异常，它会在用户按 Ctrl-C 组合键的时候发生。\n",
    "\n",
    "这里，我们按下 Ctrl-C。可以看到，代码提示我们\"输入中断\"，这表示代码成功捕获了 KeyboardInterrupt 这个异常；此外，我们看到\"这句话总是被执行\"也打印了出来。\n",
    "\n",
    "我们再来试一下，这一次我们输入 abc，触发 ValueError。可以看到，代码提示我们输入错误，并且这时也执行了 finally 子句。\n",
    "\n",
    "最后，我们输入一个正确的数字 42 试一下。大家可以看到，else 子句被执行了，这个子句只会在我们输入正确，没有触发异常的时候运行。\n",
    "\n",
    "此外，finally 子句也运行了，这就是 finally 关键字的作用，它在无论何种异常情况下都能执行。这个特性在做一些清理工作，例如关闭文件、缓存、数据库连接等方面尤其有用。\n",
    "\n",
    "我们上面这种写法，用 except 语句捕获并处理了不同的异常，实现了不同的异常情况区别对待的功能。\n",
    "\n",
    "假如说有若干个异常情况可以做同样的处理，except 也是可以同时捕获多种不同类型异常的，写法类似 except (XXXError, YYYError, ZZZError): ；"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "此外，except 后面也可以不写任何异常类型，这时 except 就会尝试捕获所有发生的异常。不过，可乐不建议大家盲目地捕获所有的异常，一方面是这样我们可能掩盖了代码中的严重错误；另一方面，盲目捕获所有异常也是一种偷懒的做法，总是这么做，你就没有动力研究各种可能发生的异常了。  \n",
    "\n",
    "最后，except 语句还支持用 as 关键字将捕获的异常赋值给一个变量；捕获的异常处理之后还可以使用 raise 语句抛出；并且，我们也能够定义自己的异常类型。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "好了，今天的课程可乐就先讲到这里。写代码难免遇到错误和异常，而在大型代码中异常处理更是尤为重要。在使用内置函数、第三方库时，大家可以多查阅文档，看看别人写的函数是否会抛出异常，又会抛出什么样的异常，需要做什么样的处理。希望大家以后在写代码的时候，都能认真思考，勤于调研，写出不倒翁一样稳定的代码哦。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
